#include "specialtablemodel.h"


#include <classlevel.h>


#include <QStringList>
#include <QDebug>
#include <QRegExp>


SpecialTableModel::SpecialTableModel(QObject *parent) :
    QAbstractTableModel(parent)
{
}

void SpecialTableModel::setCampaign(Campaign *campaign)
{
    if (m_campaign.data() == campaign)
    {
        return;
    }

    beginResetModel();
    m_specialAbilities = 0;
    m_characterClasses = 0;
    m_campaign = campaign;

    if (!m_campaign.isNull())
    {
        m_specialAbilities = m_campaign->findChild<SpecialAbilities*>(QString(), Qt::FindDirectChildrenOnly);
        m_characterClasses = m_campaign->findChild<CharacterClasses*>(QString(), Qt::FindDirectChildrenOnly);
    }
    endResetModel();
}

int SpecialTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)

    if (!ready())
    {
        return 0;
    }

    int ret = 0;
    foreach (const CharacterClass* characterClass, m_characterClasses->findChildren<const CharacterClass*>(QString(), Qt::FindDirectChildrenOnly))
    {
        int levels = characterClass->findChildren<const ClassLevel*>().count();
        if (!levels)
        {
            qDebug() << Q_FUNC_INFO << characterClass->name() << "does not have levels!";
        }

        if (levels <= ret)
        {
            continue;
        }

        ret = levels;
    }

    return ret;
}

int SpecialTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)

    if (!ready())
    {
        return 0;
    }

    return m_characterClasses->findChildren<const CharacterClass*>(QString(), Qt::FindDirectChildrenOnly).count();
}

QVariant SpecialTableModel::data(const QModelIndex &index, int role) const
{
    if (role != Qt::DisplayRole && role != Role_CharacterClass && role != Qt::TextAlignmentRole && role != Qt::EditRole)
    {
        return QVariant();
    }

    if (role == Qt::TextAlignmentRole)
    {
        return Qt::AlignTop;
    }

    QList<CharacterClass*> classList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    if (index.column() < 0 || index.column() >= classList.count())
    {
        return QVariant();
    }

    CharacterClass* characterClass = classList.at(index.column());
    if (role == Role_CharacterClass)
    {
        return characterClass->name();
    }

    QList<const ClassLevel*> levelList = characterClass->findChildren<const ClassLevel*>();
    if (index.row() < 0 || index.row() >= levelList.count())
    {
        return QVariant();
    }

    const ClassLevel* level = levelList.at(index.row());

    QStringList specialAbilityNames;

    foreach (SpecialAbility* specialAbility, level->findChildren<SpecialAbility*>(QString(), Qt::FindDirectChildrenOnly))
    {
        QString name = specialAbility->name();
        if (name.isEmpty())
        {
            name = "[nameless]";
        }

        specialAbilityNames << name;
    }

    qSort(specialAbilityNames);

    if (role == Qt::DisplayRole)
    {
        return specialAbilityNames.join(", ");
    }

    return specialAbilityNames;
}

bool SpecialTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!ready() || !index.isValid() || role != Qt::EditRole)
    {
        return false;
    }

    QList<CharacterClass*> classList = m_characterClasses->findChildren<CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    if (index.column() < 0 || index.column() >= classList.count())
    {
        return false;
    }

    CharacterClass* characterClass = classList.at(index.column());

    ClassLevels* classLevels = characterClass->findChild<ClassLevels*>(QString(), Qt::FindDirectChildrenOnly);
    QList<ClassLevel*> levelList = classLevels->findChildren<ClassLevel*>(QString(), Qt::FindDirectChildrenOnly);
    if (index.row() < 0 || index.column() >= levelList.count())
    {
        return false;
    }

    ClassLevel* level = levelList.at(index.row());

    QStringList newValues = qvariant_cast<QStringList>(value);
    foreach (SpecialAbility* specialAbility, level->findChildren<SpecialAbility*>(QString(), Qt::FindDirectChildrenOnly))
    {
        if (!newValues.contains(specialAbility->name()))
        {
            specialAbility->deleteLater();
            continue;
        }

        newValues.removeAll(specialAbility->name());
    }


    foreach (QString specialAbilityName, newValues)
    {
        specialAbilityName = specialAbilityName.simplified();
        QRegExp re(QString("*.%1").arg(specialAbilityName), Qt::CaseInsensitive, QRegExp::Wildcard);

        QList<SpecialAbility*> specialAbilityList = m_specialAbilities->findChildren<SpecialAbility*>(re, Qt::FindDirectChildrenOnly);

        SpecialAbility* specialAbility = 0;
        if (specialAbilityList.isEmpty())
        {
            specialAbility = qobject_cast<SpecialAbility*>(m_specialAbilities->newChild(specialAbilityName));
            qDebug() << Q_FUNC_INFO << "Created new special ability:" << specialAbility->name() << specialAbility->objectName();
        }
        else
        {
            if (specialAbilityList.count() > 1)
            {
                qWarning() << Q_FUNC_INFO << "Multiple special abilities found with:" << specialAbilityName;
            }
            specialAbility = specialAbilityList.first();
        }

        SpecialAbility* classSpecialAbility = qobject_cast<SpecialAbility*>(level->newChild());
        classSpecialAbility->setReferenceItem(specialAbility);
    }

    emit dataChanged(index, index);
    return true;
}

QVariant SpecialTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role != Qt::DisplayRole && role != SpecialTableModel::Role_CharacterClass)
    {
        return QAbstractTableModel::headerData(section, orientation, role);
    }

    if (orientation == Qt::Vertical)
    {
        return section + 1;
    }

    QList<const CharacterClass*> classList = m_characterClasses->findChildren<const CharacterClass*>(QString(), Qt::FindDirectChildrenOnly);
    if (section < 0 || section >= classList.count())
    {
        return QVariant();
    }

    const CharacterClass* characterClass = classList.at(section);

    return characterClass->name();
}

Qt::ItemFlags SpecialTableModel::flags(const QModelIndex &index) const
{
//    return QAbstractTableModel::flags(index);
    return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
}


bool SpecialTableModel::ready() const
{
    return (!m_campaign.isNull() && !m_characterClasses.isNull() && !m_specialAbilities.isNull());
}

void SpecialTableModel::revert()
{
    emit layoutAboutToBeChanged();
    emit layoutChanged();
}
